/*
异步日志
*/

#pragma once

#include <stdio.h>
#include <string>
#include <list>
#include <thread>
#include <memory>
#include <mutex>
#include <condition_variable>

enum LOG_LEVEL
{
    LOG_LEVEL_TRACE,
    LOG_LEVEL_DEBUG,
    LOG_LEVEL_INFO,
    LOG_LEVEL_WARNING,
    LOG_LEVEL_ERROR,       //业务错误
    LOG_LEVEL_SYSERROR,    //框架本身错误
    LOG_LEVEL_FATAL,       //该级别日志输出后，进程退出
    LOG_LEVEL_CRITICAL     //不受级别控制，总是输出
};

class AsyncLog
{
public:
    static bool init(const char* pszLogFileName = nullptr, bool bTruncateLongLine = false, int64_t nRollSize = 10*1024*1024);
    static void uninit();

    static void setLevel(LOG_LEVEL nLevel);
    static bool isRunning();

    //不输出线程ID和所在函数签名、行号
    static bool output(long nLevel,const char* pszFmt, ...);
    //输出线程ID和所在函数签名、行号
    static bool output(long nLevel,const char* pszFileName, int LineNo, const char* pszFmt, ...);
    //输出缓冲区
    static bool outputBinary(unsigned char* buffer,size_t size);

private:
    AsyncLog() = delete;
    ~AsyncLog() = delete;

    AsyncLog(AsyncLog&) = delete;
    AsyncLog& operator=(AsyncLog&) = delete;

    static void makeLinePrefix(long nLevel, const std::string& prefix);
    static void getTime(char* pszTime, int TimeStrLength);
    static bool createNewFile(const char* pszFileName);
    static bool writeToFile(const std::string& data);
    static void crash();    //让程序主动奔溃

    static const char*ullto4Str(int n);
    static char* formLog(int &index, char* szbuf, size_t sizeBuff, unsigned char* buffer,size_t size);
    static void writeThreadProc();

private:
    static bool                             m_bToFile;              //日志写入文件还是控制台
    static FILE*                            m_hlogFIle; 
    static std::string                      m_strFileName;          //日志名
    static std::string                      m_strFileNamePID;       //文件名中的进程的pid
    static bool                             m_bTruncateLongLog;     //长日志是否截断
    static LOG_LEVEL                        m_nCurrentLevel;        //当前日志级别
    static int64_t                          m_nFileRollSize;        //单个日志文件的最大字节数
    static int64_t                          m_nCurrentWrittenSize;  //已经写入的字节数目
    static std::list<std::string>           m_listLinesToWritten;   //待写入的日志列表
    static std::shared_ptr<std::thread>     m_spWrittenThread;  
    static std::mutex                       m_mutexWrite;
    static std::condition_variable          m_cvWrite;
    static bool                             m_bExit;                //退出标志
    static bool                             m_bRunning;             //运行标志

};

